package com.zhulanhua.blogs.exception;

import com.zhulanhua.blogs.Utils.Code;
import com.zhulanhua.blogs.Utils.Result;
import lombok.extern.log4j.Log4j2;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
@Log4j2
public class ProjectExceptionAdvice {

    @ExceptionHandler(Throwable.class)
    public Result error(Exception e) {
        return  new Result(Code.SYSTEM_ERR, null, e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleMethodArgumentNotValid(Exception e) {
        MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
        BindingResult bindingResult = ex.getBindingResult();
        Map<String, Object> map = new HashMap<>();
        String field = "";
        for (FieldError error : bindingResult.getFieldErrors()) {
            field = error.getField();
            String msg = error.getDefaultMessage();
            map.put(field, msg);
        }
        return new Result(Code.PARAMS_ERR, map, (String) map.get(field));
    }

    /**
     * 用户 token 权限
     * @return
     */
    @ExceptionHandler(value = TokenAuthExpiredException.class)
    public Result tokenExpiredExceptionHandler(TokenAuthExpiredException ex){
        log.warn(ex.getMessage());
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    /**
     * 参数异常
     * @return
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public Result MissingServletRequestParameterException(MissingServletRequestParameterException ex){
        ex.printStackTrace();
        log.error(ex.getMessage());
        return new Result(Code.PARAMS_ERR, null, "参数异常");
    }

    /**
     * 后端的实体类与前端的传入参数数据不一样
     * @return
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public Result MissingServletRequestParameterException(HttpMessageNotReadableException ex){
        ex.printStackTrace();
        log.error(ex.getMessage());
        return new Result(Code.PARAMS_ERR, null, "后端的实体类与前端的传入参数数据不一样");
    }

    /**
     * 数据在数据库重复
     * @return
     */
    @ExceptionHandler(value = DuplicateKeyException.class)
    public Result MissingServletRequestParameterException(DuplicateKeyException ex){
        ex.printStackTrace();
        log.error(ex.getMessage());
        return new Result(Code.BUSINESS_ERR, null, "数据在数据库重复");
    }

    /**
     * 404页面
     * @return
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    public Result MissingServletRequestParameterException(NoHandlerFoundException ex){
        ex.printStackTrace();
        log.error(ex.getMessage());
        return new Result(Code.BUSINESS_ERR, null, "路径存在，请检查路径是否正确");
    }

    /**
     * 请求方式不正确
     * @return
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public Result MissingServletRequestParameterException(HttpRequestMethodNotSupportedException ex){
        ex.printStackTrace();
        log.error(ex.getMessage());
        return new Result(Code.BUSINESS_ERR, null, "请求方式不正确");
    }

    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志
        log.error(ex.getMessage());
        //发送消息给运维
        //发送邮件给开发人员，把ex对象发送
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        //记录日志
        ex.printStackTrace();
        log.error(ex.getMessage());
        //发送消息给运维
        //发送邮件给开发人员，把ex对象发送
        return new Result(Code.SYSTEM_UNKNOWN_ERR, null, "系统繁忙，请稍后再试！");
    }
}
